// ==UserScript==
// @name 喵课助手 | 网课小工具
// @namespace http://nb.zizizi.top/
// @version 1.1.2
// @description 支持【超星学习通】【智慧树】【职教云系列】【雨课堂】【考试星】【168网校】【u校园】【大学MOOC】【云班课】【优慕课】【继续教育类】【绎通云课堂】【九江系列】【柠檬文才】【亿学宝云】【优课学堂】【小鹅通】【安徽继续教育】【上海开放大学】【华侨大学自考网络助学平台】【良师在线】【和学在线】【人卫慕课】【国家开放大学】【山财培训网】【浙江省高等学校在线开放课程共享平台】【国地质大学远程与继续教育学院】【重庆大学网络教育学院】【浙江省高等教育自学考试网络助学平台】【湖南高等学历继续教育】【优学院】【学起系列】【青书学堂】【学堂在线】【英华学堂】【广开网络教学平台】等,内置题库功能。Q群:1033538224
// @author 喵课团队
// @match *://*.edu.cn/*
// @match *://*.chaoxing.com/*
// @match *://*.zhihuishu.com/*
// @match *://*.icve.com.cn/*
// @match *://*.cnmooc.org/*
// @match *://*.xuetangx.com/*
// @match *://*.icourse163.org/*
// @match *://*.yuketang.cn/*
// @match *://*.mooc.cn/*
// @match *://study.163.com/*
// @match *://www.bilibili.com/video/*
// @match *://v.qq.com/*
// @icon http://nb.zizizi.top/miaoke.ico
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// 工具类
class MiaoKeHelper {
constructor() {
this.version = '1.0';
this.siteName = this.detectSite();
this.init();
}
// 检测当前网站
detectSite() {
const host = window.location.hostname;
if (host.includes('chaoxing.com')) return '超星学习通';
if (host.includes('zhihuishu.com')) return '智慧树';
if (host.includes('icve.com.cn')) return '智慧职教';
if (host.includes('xuetangx.com')) return '学堂在线';
if (host.includes('icourse163.org')) return '中国大学MOOC';
if (host.includes('bilibili.com')) return 'B站视频';
if (host.includes('v.qq.com')) return '腾讯视频';
return '教育平台';
}
// 初始化
init() {
this.addStyles();
this.createUI();
this.initFeatures();
this.bindEvents();
console.log(`喵课助手已启动 - ${this.siteName}`);
}
// 添加样式
addStyles() {
GM_addStyle(`
/* 主容器样式 */
#miaoke-helper-btn {
position: fixed;
z-index: 9999;
right: 20px;
top: 100px;
width: 60px;
height: 60px;
border-radius: 50%;
background: linear-gradient(135deg, #6a5af9, #d66efd);
color: white;
text-align: center;
line-height: 60px;
font-size: 28px;
cursor: pointer;
box-shadow: 0 4px 20px rgba(106, 90, 249, 0.4);
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
user-select: none;
border: 2px solid rgba(255, 255, 255, 0.3);
backdrop-filter: blur(5px);
}
#miaoke-helper-btn:hover {
transform: scale(1.1) rotate(5deg);
box-shadow: 0 6px 25px rgba(106, 90, 249, 0.6);
}
#miaoke-helper-panel {
position: fixed;
z-index: 9998;
right: 20px;
top: 100px;
width: 340px;
background: rgba(255, 255, 255, 0.95);
border-radius: 16px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
font-family: 'PingFang SC', 'Microsoft YaHei', Arial, sans-serif;
transition: all 0.4s cubic-bezier(0.165, 0.84, 0.44, 1);
display: none;
overflow: hidden;
backdrop-filter: blur(10px);
border: 1px solid rgba(106, 90, 249, 0.2);
transform-origin: top right;
}
#miaoke-helper-panel.active {
display: block;
animation: panelFadeIn 0.4s forwards;
}
@keyframes panelFadeIn {
from {
opacity: 0;
transform: translateY(-20px) scale(0.95);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
/* 面板头部 */
.helper-header {
padding: 18px 20px;
background: linear-gradient(135deg, #6a5af9, #d66efd);
color: white;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.helper-title {
margin: 0;
font-size: 18px;
font-weight: 600;
letter-spacing: 0.5px;
display: flex;
align-items: center;
gap: 8px;
}
.helper-title:before {
content: '🐱';
display: inline-block;
font-size: 22px;
}
.helper-close {
cursor: pointer;
font-size: 22px;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: all 0.2s;
background: rgba(255, 255, 255, 0.2);
}
.helper-close:hover {
background: rgba(255, 255, 255, 0.3);
transform: rotate(90deg);
}
/* 功能区 */
.helper-content {
padding: 20px;
max-height: 450px;
overflow-y: auto;
scrollbar-width: thin;
}
.helper-content::-webkit-scrollbar {
width: 6px;
}
.helper-content::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.05);
border-radius: 3px;
}
.helper-content::-webkit-scrollbar-thumb {
background: rgba(106, 90, 249, 0.3);
border-radius: 3px;
}
.helper-section {
margin-bottom: 24px;
padding-bottom: 8px;
position: relative;
}
.section-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 14px;
color: #333;
border-bottom: 2px solid #eee;
padding-bottom: 8px;
position: relative;
}
.section-title:after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 50px;
height: 2px;
background: linear-gradient(90deg, #6a5af9, #d66efd);
}
.feature-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 10px;
}
.feature-btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
padding: 10px 16px;
background: #f5f5f5;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
color: #444;
transition: all 0.3s;
border: 1px solid #e0e0e0;
min-width: 90px;
}
.feature-btn:before {
font-size: 16px;
}
#auto-play:before { content: '▶️'; }
#reading-mode:before { content: '📖'; }
#take-notes:before { content: '📝'; }
#speed-control:before { content: '⏱️'; }
#auto-next:before { content: '⏭️'; }
.feature-btn:hover {
background: #EEEAFF;
border-color: #d1caff;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(106, 90, 249, 0.1);
}
.feature-btn.active {
background: linear-gradient(135deg, #6a5af9, #d66efd);
color: white;
border-color: transparent;
box-shadow: 0 4px 15px rgba(106, 90, 249, 0.3);
}
/* 设置区域 */
.helper-setting {
margin-bottom: 14px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 15px;
background: #f8f8f8;
border-radius: 10px;
transition: all 0.3s;
border: 1px solid #eee;
}
.helper-setting:hover {
background: #f0f0f0;
border-color: #ddd;
}
.setting-label {
font-size: 14px;
color: #444;
font-weight: 500;
}
.setting-input {
width: 70px;
text-align: center;
border: 1px solid #ddd;
border-radius: 6px;
padding: 6px 8px;
font-size: 14px;
transition: all 0.3s;
background: white;
}
.setting-input:focus {
outline: none;
border-color: #6a5af9;
box-shadow: 0 0 0 3px rgba(106, 90, 249, 0.1);
}
/* 底部 */
.helper-footer {
padding: 12px 15px;
background: #f5f5f5;
text-align: center;
font-size: 12px;
color: #666;
border-top: 1px solid #eee;
}
.helper-footer a {
color: #6a5af9;
text-decoration: none;
font-weight: 500;
transition: all 0.2s;
}
.helper-footer a:hover {
color: #d66efd;
text-decoration: underline;
}
/* 笔记面板 */
#note-panel {
position: fixed;
right: 20px;
bottom: 20px;
width: 340px;
height: 300px;
background: white;
border-radius: 16px;
box-shadow: 0 8px 25px rgba(0,0,0,0.15);
z-index: 9997;
display: none;
overflow: hidden;
border: 1px solid rgba(106, 90, 249, 0.2);
transition: all 0.4s cubic-bezier(0.165, 0.84, 0.44, 1);
}
#note-panel.active {
display: block;
animation: notePanelFadeIn 0.4s forwards;
}
@keyframes notePanelFadeIn {
from {
opacity: 0;
transform: translateY(20px) scale(0.95);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.note-header {
padding: 15px;
background: linear-gradient(135deg, #6a5af9, #d66efd);
color: white;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 16px;
font-weight: 600;
}
.note-content {
padding: 15px;
height: calc(100% - 110px);
}
.note-textarea {
width: 100%;
height: 100%;
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 10px;
resize: none;
font-size: 14px;
line-height: 1.5;
transition: all 0.3s;
}
.note-textarea:focus {
outline: none;
border-color: #6a5af9;
box-shadow: 0 0 0 3px rgba(106, 90, 249, 0.1);
}
.note-footer {
padding: 10px 15px;
display: flex;
justify-content: flex-end;
background: #f5f5f5;
}
.note-save {
padding: 8px 16px;
background: linear-gradient(135deg, #6a5af9, #d66efd);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.3s;
box-shadow: 0 4px 10px rgba(106, 90, 249, 0.2);
}
.note-save:hover {
transform: translateY(-2px);
box-shadow: 0 6px 15px rgba(106, 90, 249, 0.3);
}
/* 阅读模式 */
.reading-mode-active {
background-color: #f8f9fa !important;
color: #333 !important;
font-size: 18px !important;
line-height: 1.7 !important;
letter-spacing: 0.3px !important;
}
.reading-mode-active p, .reading-mode-active div {
max-width: 900px !important;
margin: 0 auto !important;
padding: 15px 30px !important;
}
/* 拖动功能 */
.draggable {
cursor: move;
}
/* 状态提示 */
.status-tip {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 10px 20px;
border-radius: 8px;
z-index: 10000;
font-size: 14px;
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
}
.status-tip.show {
opacity: 1;
}
/* 按钮动效 */
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.feature-btn.active:before {
animation: pulse 2s infinite;
}
/* 进度条 */
.progress-container {
width: 100%;
height: 6px;
background: #f0f0f0;
border-radius: 3px;
overflow: hidden;
margin-top: 5px;
}
.progress-bar {
height: 100%;
background: linear-gradient(90deg, #6a5af9, #d66efd);
width: 0;
transition: width 0.3s;
}
`);
}
// 创建用户界面
createUI() {
// 主按钮
const btn = document.createElement('div');
btn.id = 'miaoke-helper-btn';
btn.innerHTML = '🐱';
btn.title = '喵课助手';
document.body.appendChild(btn);
// 主面板
const panel = document.createElement('div');
panel.id = 'miaoke-helper-panel';
panel.innerHTML = `
学习辅助功能
自动播放
阅读模式
笔记工具
速度调节
自动下一章
视频状态
当前状态:
未检测到视频
自动播放:
未启用
`;
document.body.appendChild(panel);
// 笔记面板
const notePanel = document.createElement('div');
notePanel.id = 'note-panel';
notePanel.innerHTML = `
`;
document.body.appendChild(notePanel);
// 状态提示
const statusTip = document.createElement('div');
statusTip.className = 'status-tip';
statusTip.id = 'status-tip';
document.body.appendChild(statusTip);
}
// 显示状态提示
showStatusTip(message, duration = 2000) {
const tip = document.getElementById('status-tip');
tip.textContent = message;
tip.classList.add('show');
setTimeout(() => {
tip.classList.remove('show');
}, duration);
}
// 初始化功能
initFeatures() {
// 获取保存的笔记
const savedNote = GM_getValue('miaoke_helper_note_' + window.location.href, '');
if (savedNote) {
document.querySelector('.note-textarea').value = savedNote;
}
// 获取保存的设置
const savedSpeed = GM_getValue('miaoke_helper_speed', 1.5);
document.getElementById('play-speed').value = savedSpeed;
// 获取自动播放设置
const autoPlayEnabled = GM_getValue('miaoke_helper_autoplay', true);
if (autoPlayEnabled) {
document.getElementById('auto-play').classList.add('active');
this.enableAutoPlay();
}
}
// 绑定事件
bindEvents() {
const self = this;
// 主按钮点击
document.getElementById('miaoke-helper-btn').addEventListener('click', function() {
const panel = document.getElementById('miaoke-helper-panel');
panel.classList.toggle('active');
});
// 关闭按钮
document.querySelectorAll('.helper-close').forEach(function(el) {
el.addEventListener('click', function() {
this.closest('#miaoke-helper-panel, #note-panel').classList.remove('active');
});
});
// 自动播放
document.getElementById('auto-play').addEventListener('click', function() {
this.classList.toggle('active');
if (this.classList.contains('active')) {
self.enableAutoPlay();
GM_setValue('miaoke_helper_autoplay', true);
self.showStatusTip('已开启自动播放功能', 1500);
} else {
self.disableAutoPlay();
GM_setValue('miaoke_helper_autoplay', false);
self.showStatusTip('已关闭自动播放功能', 1500);
}
});
// 阅读模式
document.getElementById('reading-mode').addEventListener('click', function() {
this.classList.toggle('active');
document.body.classList.toggle('reading-mode-active');
});
// 笔记工具
document.getElementById('take-notes').addEventListener('click', function() {
document.getElementById('note-panel').classList.toggle('active');
});
// 保存笔记
document.querySelector('.note-save').addEventListener('click', function() {
const noteContent = document.querySelector('.note-textarea').value;
GM_setValue('miaoke_helper_note_' + window.location.href, noteContent);
self.showStatusTip('笔记已保存!', 1500);
});
// 速度调节
document.getElementById('speed-control').addEventListener('click', function() {
this.classList.toggle('active');
const speedSettings = document.getElementById('speed-settings');
speedSettings.style.display = speedSettings.style.display === 'none' ? 'block' : 'none';
});
// 应用速度
document.getElementById('apply-speed').addEventListener('click', function() {
const speedValue = parseFloat(document.getElementById('play-speed').value);
GM_setValue('miaoke_helper_speed', speedValue);
self.applyVideoSpeed(speedValue);
self.showStatusTip(`已将视频速度设为 ${speedValue}x`, 1500);
});
// 自动下一章
document.getElementById('auto-next').addEventListener('click', function() {
this.classList.toggle('active');
if (this.classList.contains('active')) {
self.enableAutoNext();
self.showStatusTip('已开启自动下一章功能', 1500);
} else {
self.disableAutoNext();
self.showStatusTip('已关闭自动下一章功能', 1500);
}
});
// 拖动功能
this.enableDrag(document.querySelectorAll('.draggable'));
}
// 启用自动播放
enableAutoPlay() {
// 立即尝试播放当前视频
this.autoPlayVideos();
// 更新自动播放状态
document.getElementById('autoplay-status').textContent = '已启用';
document.getElementById('autoplay-status').style.color = '#6a5af9';
// 监听 DOM 变化以捕捉新加载的视频
if (!this.mutationObserver) {
this.mutationObserver = new MutationObserver((mutations) => {
this.autoPlayVideos();
});
this.mutationObserver.observe(document.body, {
childList: true,
subtree: true
});
}
// 定时检查是否有需要播放的视频
if (!this.autoPlayInterval) {
this.autoPlayInterval = setInterval(() => {
this.autoPlayVideos();
this.handlePopupDialogs();
this.updateVideoStatus();
}, 1000);
}
}
// 实际处理自动播放的函数
autoPlayVideos() {
// 获取所有视频元素
const videos = document.querySelectorAll('video');
if (videos.length > 0) {
// 更新视频状态
document.getElementById('video-status').textContent = '已检测到视频';
document.getElementById('video-status').style.color = '#6a5af9';
// 播放每个视频
videos.forEach(video => {
// 为视频添加事件监听器(如果尚未添加)
if (!video.hasAttribute('miaoke-processed')) {
// 添加播放错误处理
video.addEventListener('error', () => {
console.log('视频播放出错');
this.showStatusTip('视频播放出错,尝试恢复...', 2000);
setTimeout(() => this.clickPlayButton(), 500);
});
// 添加进度更新
video.addEventListener('timeupdate', () => {
this.updateVideoProgress(video);
});
// 添加视频结束处理
video.addEventListener('ended', () => {
if (document.getElementById('auto-next').classList.contains('active')) {
setTimeout(() => this.findAndClickNextButton(), 1000);
}
});
video.setAttribute('miaoke-processed', 'true');
}
// 如果视频暂停或未播放
if (video.paused && !video.ended) {
// 尝试自动点击页面上的播放按钮
this.clickPlayButton();
// 同时尝试直接播放视频元素
const playPromise = video.play();
// 处理可能的错误
if (playPromise !== undefined) {
playPromise.catch(error => {
console.log('自动播放失败,尝试备用方法:', error.message);
// 备用方法:模拟用户交互后再尝试播放
setTimeout(() => {
// 短暂聚焦视频元素
video.focus();
// 模拟点击视频
video.click();
// 再次尝试播放
video.play().catch(e => {
console.log('第二次播放尝试也失败:', e.message);
// 最后的方法:尝试特定站点的解决方案
this.trySiteSpecificAutoplay();
});
}, 300);
});
}
}
// 应用当前设置的速度
const currentSpeed = parseFloat(document.getElementById('play-speed').value);
if (video.playbackRate !== currentSpeed) {
video.playbackRate = currentSpeed;
}
});
} else {
// 没有视频的情况
document.getElementById('video-status').textContent = '未检测到视频';
document.getElementById('video-status').style.color = '#888';
// 重置进度条
const progressBar = document.getElementById('video-progress');
progressBar.style.width = '0%';
}
}
// 尝试特定网站的自动播放解决方案
trySiteSpecificAutoplay() {
switch(this.siteName) {
case '超星学习通':
// 超星特定解决方案
const chaoxingPlayBtns = document.querySelectorAll('.vjs-big-play-button, .vjs-play-control');
chaoxingPlayBtns.forEach(btn => btn.click());
break;
case '智慧树':
// 智慧树特定解决方案
const zhihuishuPlayBtns = document.querySelectorAll('.playButton, .controlsBar__playButton');
zhihuishuPlayBtns.forEach(btn => btn.click());
break;
case '中国大学MOOC':
// 中国大学MOOC特定解决方案
const moocPlayBtns = document.querySelectorAll('.ux-video-player .ux-controls-panel .btn-play');
moocPlayBtns.forEach(btn => btn.click());
break;
case 'B站视频':
// B站特定解决方案
const biliPlayBtns = document.querySelectorAll('.bilibili-player-video-btn-start');
biliPlayBtns.forEach(btn => btn.click());
break;
default:
// 通用解决方案:尝试通过iframe查找视频
const iframes = document.querySelectorAll('iframe');
iframes.forEach(iframe => {
try {
const iframeVideos = iframe.contentDocument.querySelectorAll('video');
iframeVideos.forEach(video => {
video.play().catch(e => console.log('iframe视频播放失败:', e.message));
});
// 尝试点击iframe内的按钮
const iframePlayBtns = iframe.contentDocument.querySelectorAll('[class*="play"], [id*="play"], .play-btn');
iframePlayBtns.forEach(btn => btn.click());
} catch(e) {
console.log('无法访问iframe内容,可能是跨域限制');
}
});
}
}
// 更新视频状态
updateVideoStatus() {
const videos = document.querySelectorAll('video');
if (videos.length > 0) {
let anyPlaying = false;
videos.forEach(video => {
if (!video.paused && !video.ended) {
anyPlaying = true;
// 更新当前播放中的视频进度
this.updateVideoProgress(video);
}
});
const statusText = document.getElementById('video-status');
if (anyPlaying) {
statusText.textContent = '播放中';
statusText.style.color = '#4CAF50';
} else if (videos[0].ended) {
statusText.textContent = '已播放完毕';
statusText.style.color = '#FF9800';
} else {
statusText.textContent = '已暂停';
statusText.style.color = '#F44336';
}
}
}
// 更新视频进度条
updateVideoProgress(video) {
if (!video) return;
// 计算百分比
const percent = (video.currentTime / video.duration) * 100;
const progressBar = document.getElementById('video-progress');
if (!isNaN(percent) && isFinite(percent)) {
progressBar.style.width = `${percent}%`;
// 更新速度进度条
const speedProgressBar = document.getElementById('speed-progress');
if (speedProgressBar) {
const speedPercent = Math.min(100, (parseFloat(document.getElementById('play-speed').value) / 16) * 100);
speedProgressBar.style.width = `${speedPercent}%`;
}
}
}
// 点击可能的播放按钮
clickPlayButton() {
// 常见的播放按钮选择器
const playButtonSelectors = [
'.videojs-player .vjs-big-play-button',
'.video-js .vjs-big-play-button',
'.prism-player .prism-big-play-btn',
'.jwplayer .jw-display-icon-container',
'.video-player .play-btn',
'[aria-label="播放"]',
'[title="播放"]',
'[class*="play-button"]',
'[class*="play_btn"]',
'[class*="playButton"]',
'[id*="play-button"]',
'[id*="play_btn"]',
'[id*="playButton"]',
'button:contains("播放")',
'div:contains("继续学习")',
'.play', '.start', '.begin', '.continue',
// B站特定
'.bilibili-player-video-btn-start',
// 超星特定
'.vjs-play-control',
// 智慧树特定
'.playButton', '.controlsBar__playButton',
// 通用选择器
'svg[class*="play"]',
'i[class*="play"]'
];
// 尝试点击匹配到的按钮
let buttonClicked = false;
for (let selector of playButtonSelectors) {
const buttons = document.querySelectorAll(selector);
if (buttons.length > 0) {
buttons.forEach(button => {
button.click();
buttonClicked = true;
console.log('点击了播放按钮: ' + selector);
});
if (buttonClicked) break;
}
}
// 如果没找到按钮,尝试在iframe中查找
if (!buttonClicked) {
const iframes = document.querySelectorAll('iframe');
iframes.forEach(iframe => {
try {
for (let selector of playButtonSelectors) {
const iframeButtons = iframe.contentDocument.querySelectorAll(selector);
iframeButtons.forEach(button => {
button.click();
buttonClicked = true;
console.log('点击了iframe中的播放按钮: ' + selector);
});
if (buttonClicked) break;
}
} catch(e) {
console.log('无法访问iframe内容,可能是跨域限制');
}
});
}
return buttonClicked;
}
// 处理弹窗和对话框
handlePopupDialogs() {
// 处理常见的弹窗
const dialogSelectors = [
'.video-answer', // 超星的视频浏览会有的弹题
'.question-wrapper', // 智慧树的题目
'.dialog-test', // 一般测试弹窗
'.popbox', // 常见弹窗
'[class*="dialog"]', // 包含 dialog 的类
'[class*="popup"]', // 包含 popup 的类
'[class*="alert"]', // 包含 alert 的类
'[class*="modal"]', // 包含 modal 的类
// 特定平台的选择器
'.ans-videoquiz', // 超星弹题
'.ans-videoquiz-opt', // 超星选项
'.topic-item' // 智慧树题目
];
// 尝试处理匹配到的弹窗
let dialogHandled = false;
for (let selector of dialogSelectors) {
const dialogs = document.querySelectorAll(selector);
for (let dialog of dialogs) {
if (dialog && (dialog.style.display !== 'none' && dialog.offsetParent !== null)) {
// 尝试自动回答问题(对超星和智慧树常见的选择题)
if (this.tryToAnswerQuestion(dialog)) {
dialogHandled = true;
continue;
}
// 尝试找到并点击关闭按钮
const closeButtons = dialog.querySelectorAll('button, .close, .btn-close, [class*="close"], [class*="cancel"], a[href="#"]');
for (let button of closeButtons) {
if (button.innerText.includes('关闭') ||
button.innerText.includes('取消') ||
button.innerText.includes('继续') ||
button.innerText.includes('确定') ||
button.className.includes('close')) {
button.click();
console.log('自动关闭了弹窗');
dialogHandled = true;
break;
}
}
if (dialogHandled) break;
}
}
if (dialogHandled) break;
}
// 特殊处理:超星学习通的弹题
if (!dialogHandled && this.siteName === '超星学习通') {
// 超星特定的弹题处理
const topicMenus = document.querySelectorAll('.topic-menu, .ans-videoquiz');
if (topicMenus.length > 0) {
// 尝试寻找继续按钮
const continueButtons = document.querySelectorAll('div[onclick*="continue"], a:contains("继续学习"), .ans-videoquiz-submit');
if (continueButtons.length > 0) {
continueButtons[0].click();
dialogHandled = true;
}
// 如果没找到继续按钮,尝试自动选择答案
if (!dialogHandled) {
const options = document.querySelectorAll('.ans-videoquiz-opt');
if (options.length > 0) {
// 默认选第一个
options[0].click();
// 寻找提交按钮
setTimeout(() => {
const submitBtn = document.querySelector('.ans-videoquiz-submit');
if (submitBtn) submitBtn.click();
}, 500);
}
}
}
}
return dialogHandled;
}
// 尝试自动回答问题
tryToAnswerQuestion(dialog) {
// 检查是否有选项
const options = dialog.querySelectorAll('input[type="radio"], input[type="checkbox"], .ans-videoquiz-opt');
if (options.length === 0) return false;
// 智慧树和超星平台的问题处理
if (this.siteName === '智慧树' || this.siteName === '超星学习通') {
// 随机选择一个选项(或第一个)
const option = options[0];
option.click();
// 查找提交按钮
setTimeout(() => {
const submitBtns = dialog.querySelectorAll('button[type="submit"], .submit-btn, .ans-videoquiz-submit, [class*="submit"]');
if (submitBtns.length > 0) {
submitBtns[0].click();
return true;
}
}, 500);
}
return false;
}
// 禁用自动播放
disableAutoPlay() {
if (this.mutationObserver) {
this.mutationObserver.disconnect();
this.mutationObserver = null;
}
if (this.autoPlayInterval) {
clearInterval(this.autoPlayInterval);
this.autoPlayInterval = null;
}
// 更新自动播放状态
document.getElementById('autoplay-status').textContent = '已禁用';
document.getElementById('autoplay-status').style.color = '#888';
}
// 启用自动下一章
enableAutoNext() {
if (this.autoNextInterval) {
clearInterval(this.autoNextInterval);
}
this.autoNextInterval = setInterval(() => {
const videos = document.querySelectorAll('video');
videos.forEach(video => {
if (video.ended) {
this.findAndClickNextButton();
}
});
}, 2000);
}
// 禁用自动下一章
disableAutoNext() {
if (this.autoNextInterval) {
clearInterval(this.autoNextInterval);
this.autoNextInterval = null;
}
}
// 寻找并点击下一章按钮
findAndClickNextButton() {
// 针对不同平台查找下一章按钮
let nextBtn = null;
// 超星学习通
if (this.siteName === '超星学习通') {
nextBtn = document.querySelector('.ans-job-icon[title="下一章"]') ||
document.querySelector('.nextChapter');
}
// 智慧树
else if (this.siteName === '智慧树') {
nextBtn = document.querySelector('.next-page-btn') ||
document.querySelector('.next-btn');
}
// 智慧职教
else if (this.siteName === '智慧职教') {
nextBtn = document.querySelector('.next_lesson') ||
document.querySelector('.next-lesson');
}
// 其他平台的通用选择器
else {
const possibleSelectors = [
'.next', '.next-btn', '.next-lesson', '.nextChapter',
'[title="下一章"]', '[title="下一节"]', '[title="下一讲"]',
'a:contains("下一章")', 'a:contains("下一节")'
];
for (let selector of possibleSelectors) {
nextBtn = document.querySelector(selector);
if (nextBtn) break;
}
}
if (nextBtn) {
nextBtn.click();
console.log('已自动跳转至下一章');
}
}
// 设置视频速度
applyVideoSpeed(speed) {
const videos = document.querySelectorAll('video');
videos.forEach(video => {
video.playbackRate = speed;
});
// 持续应用速度(防止视频网站重置)
if (this.speedInterval) {
clearInterval(this.speedInterval);
}
this.speedInterval = setInterval(() => {
const videos = document.querySelectorAll('video');
videos.forEach(video => {
if (video.playbackRate !== speed) {
video.playbackRate = speed;
}
});
// 更新速度进度条
const speedProgressBar = document.getElementById('speed-progress');
if (speedProgressBar) {
const speedPercent = Math.min(100, (speed / 16) * 100);
speedProgressBar.style.width = `${speedPercent}%`;
}
// 在面板上显示当前速度
const statusText = document.getElementById('video-status');
if (statusText && statusText.textContent.includes('播放中')) {
statusText.textContent = `播放中 (${speed}x)`;
}
}, 1000);
// 显示状态提示
this.showStatusTip(`视频速度已设置为 ${speed}x`, 2000);
}
// 启用拖动功能
enableDrag(elements) {
elements.forEach(el => {
el.addEventListener('mousedown', (e) => {
const target = el.closest('#miaoke-helper-panel, #note-panel, #miaoke-helper-btn');
if (!target) return;
// 初始位置
const initialX = e.clientX;
const initialY = e.clientY;
const startLeft = target.offsetLeft;
const startTop = target.offsetTop;
// 移动处理函数
const moveHandler = (e) => {
const dx = e.clientX - initialX;
const dy = e.clientY - initialY;
target.style.left = startLeft + dx + 'px';
target.style.top = startTop + dy + 'px';
};
// 释放处理函数
const upHandler = () => {
document.removeEventListener('mousemove', moveHandler);
document.removeEventListener('mouseup', upHandler);
};
document.addEventListener('mousemove', moveHandler);
document.addEventListener('mouseup', upHandler);
});
});
}
}
// 页面加载完成后初始化
window.addEventListener('load', () => {
// 延迟一点时间确保页面元素都已加载
setTimeout(() => {
window.miaokeHelper = new MiaoKeHelper();
}, 1500);
});
})();